

#include <stdio.h>
#include <stdlib.h>
#include "mythread.h"

#define NUM_THREADS	5
#define CONCURRENCY	1

/* Keep track of the thread numbers */
int numThrd = 0;
/* Mutex for printing safely */
pthread_mutex_t printLock = PTHREAD_MUTEX_INITIALIZER; /* Guarantees that no two threads can print at once */

/**
 * Tests the scheduler functionality by announcing which thread is running each time the loop completes
 *
 *@param num  Integer variable representing the number of the thread running
 */
void *testScheduler(void *num){
	/* Save the thread number in inputNum, so that the pointer doesn't change during execution */
	int *inNum = (int *) num;
	int inputNum = *inNum;
	numThrd++;
	
	int i,j,k; 

	for(k=0;k<10;k++){
		for(i=0;i<1000;i++)
			for(j=0;j<2000;j++){
			}
		mythread_t current = mythread_self();
		int prio = current->dprio;
		pthread_mutex_lock(&printLock);
		printf("Thread %d with priority %d: Hello, World!!!!\n", inputNum, prio);
		pthread_mutex_unlock(&printLock);
	}
	
	mythread_exit(NULL);
}

/**
 * Main function, sets up the threads
 *
 *@param argc  Number of arguments
 *@param argv  Arguments to the function
 *@return  Integer indicating proper or improper exit
 */
int main (int argc, char *argv[]){
    mythread_t thread[NUM_THREADS];
    int tNum = 0;
    int errorCheck;
	
	mythread_setconcurrency(CONCURRENCY);

	/* Set different priority attributes to be used in different threads */
	mythread_attr_t prio1;
	mythread_attr_t prio2;
	mythread_attr_t prio3;
	mythread_attr_t prio4;
	mythread_attr_t prio5;
	
	struct sched_param param;
	param.sched_priority = 10;
	
	mythread_attr_setschedparam (&prio1,&param);
	int current = mythread_attr_getschedparam (&prio1,NULL);
	printf("Current sched_priority is: %d\n", current);
	
	param.sched_priority = 30;
	
	mythread_attr_setschedparam (&prio2,&param);
	current = mythread_attr_getschedparam (&prio2,NULL);
	printf("Current sched_priority is: %d\n", current);
	
	param.sched_priority = 100;
	
	mythread_attr_setschedparam (&prio3,&param);
	current = mythread_attr_getschedparam (&prio3,NULL);
	printf("Current sched_priority is: %d\n", current);
	
	param.sched_priority = 150;

	mythread_attr_setschedparam (&prio4,&param);
	current = mythread_attr_getschedparam (&prio4,NULL);
	printf("Current sched_priority is: %d\n", current);
	
	param.sched_priority = 200;
	
	mythread_attr_setschedparam (&prio5,&param);
	current = mythread_attr_getschedparam (&prio5,NULL);
	printf("Current sched_priority is: %d\n", current);
	
	/* Create the threads with thre priorities specified in the attributes above, prio1 through prio5 */
	errorCheck = mythread_create(&thread[0], &prio1, testScheduler, (void *) &numThrd);
	if (errorCheck)
	{
		printf("ERROR; return code from mythread_create() for thread %d is %d\n", tNum, errorCheck);
		exit(-1);
    }
		
	errorCheck = mythread_create(&thread[1], &prio2, testScheduler, (void *) &numThrd);
	if (errorCheck)
	{
		printf("ERROR; return code from mythread_create() for thread %d is %d\n", tNum, errorCheck);
		exit(-1);
    }
		
	errorCheck = mythread_create(&thread[2], &prio3, testScheduler, (void *) &numThrd);
	if (errorCheck)
	{
		printf("ERROR; return code from mythread_create() for thread %d is %d\n", tNum, errorCheck);
		exit(-1);
    }
		
	errorCheck = mythread_create(&thread[3], &prio4, testScheduler, (void *) &numThrd);
	if (errorCheck)
	{
		printf("ERROR; return code from mythread_create() for thread %d is %d\n", tNum, errorCheck);
		exit(-1);
    }

	errorCheck = mythread_create(&thread[4], &prio5, testScheduler, (void *) &numThrd);
	if (errorCheck)
	{
		printf("ERROR; return code from mythread_create() for thread %d is %d\n", tNum, errorCheck);
		exit(-1);
    }
   
    /* Join the threads */
    void *status;
    for(tNum = 0; tNum < NUM_THREADS; tNum++){
		errorCheck = mythread_join(thread[tNum], &status);
		if (errorCheck){
			printf("ERROR; return code from mythread_join() for thread %d is %d\n", tNum, errorCheck);
			exit(-1);
        }
    }

	/* printf("Main thread exiting via mythread_exit.\n"); */
	mythread_exit(NULL);

	return 0;
}
